/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/

#ifndef _BITESTREAM_H_
#define _BITESTREAM_H_

// Obsolete
//#include "gimprotocoltypes.h"

// List of reserved tag-values for different protocols.
/**
 * This file defines the reserved tag-values for using BiteStream
 */

// range of allowed values for numeric tags for users of bitestream
#ifndef BS_TAG_MIN
	#define BS_TAG_MIN     100
#endif

#ifndef BS_TAG_MAX
	#define BS_TAG_MAX     16777215
#endif

/**
 * Tag-values used by GIMI.
 */
#define GIM_PROTOCOL_GIMI_MESSAGE                   (BS_TAG_MIN+101)
#define GIMITAG_UID                                 (BS_TAG_MIN+102)
#define GIMITAG_ACTION                              (BS_TAG_MIN+103)
#define GIMITAG_MAJORTYPE                           (BS_TAG_MIN+104)
#define GIMITAG_MINORTYPE                           (BS_TAG_MIN+105)
#define GIMITAG_MSGID                               (BS_TAG_MIN+106)
#define GIMITAG_DATA                                (BS_TAG_MIN+107)
#define GIMITAG_TYPE                                (BS_TAG_MIN+108)
#define GIMITAG_COMMAND                             (BS_TAG_MIN+109)
#define GIMITAG_SERVICEDESCRIPTION                  (BS_TAG_MIN+110)
#define GIMITAG_REPLY                               (BS_TAG_MIN+111)
#define GIMITAG_SERVICELOCATION                     (BS_TAG_MIN+112)
#define GIMITAG_SERVICETYPE                         (BS_TAG_MIN+113)
#define GIMITAG_VERSION                             (BS_TAG_MIN+114)
#define GIMITAG_BUILD                               (BS_TAG_MIN+115)
#define GIMITAG_CLIENTVERSION                       (BS_TAG_MIN+116)
#define GIMITAG_CLIENTBUILD                         (BS_TAG_MIN+117)

/**
 * Tag-values used by GIMdb
 */
#define GIMDB_PROTOCOL_BINARY                       (BS_TAG_MIN+501)
#define GIMDBTAG_DBID                               (BS_TAG_MIN+502)
#define GIMDBTAG_SESSIONID                          (BS_TAG_MIN+503)
#define GIMDBTAG_NODELIST                           (BS_TAG_MIN+504)
#define GIMDBTAG_ENDNODELIST                        (BS_TAG_MIN+505)
#define GIMDBTAG_NODE                               (BS_TAG_MIN+506)
#define GIMDBTAG_ENDNODE                            (BS_TAG_MIN+507)
#define GIMDBTAG_NODE_ENTRYID                       (BS_TAG_MIN+508)
#define GIMDBTAG_NODE_DATA                          (BS_TAG_MIN+509)
#define GIMDBTAG_NODE_PARAMETERNAME                 (BS_TAG_MIN+510)
#define GIMDBTAG_NODE_PARAMETERVALUE                (BS_TAG_MIN+511)
#define GIMDBTAG_NODE_ELEMENT                       (BS_TAG_MIN+512)


// range of allowed values for numeric tags for users
#ifndef BS_TAG_MIN
	#define BS_TAG_MIN  100
#endif

#ifndef BS_TAG_MAX
	#define BS_TAG_MAX  16777215
#endif


// value meaning the key is a string instead of a number
#define BS_NAMED    1



// this must be 2**n (a power of two)
#define BS_BUFLEN 1024

#ifdef __cplusplus
extern "C" {
#endif


// this struct represents any type of tag conveniently, when decoding a stream
typedef struct _bsTag {
    int     tag;        // the tag itself
    char *  name;       // pointer to name, if tag == BS_NAMED
    int     value;      // value, if the tag is an int
    int     length;     // length of the data (4 for int, includes null terminator for strings)
    char *  string;     // pointer to the data, for string tags
    void *  data;       // same as above, for binary tags (data == string)
} bsTag;


typedef struct _BiteStream {
    int     numtags;    // tags in the list
    int     length;     // bytes used (also the writing position for appends)
    int     bufsize;    // bytes in the current buffer
    int     flags;
    char *  buf;        // data buffer
    char *  pos;        // current reading position
    bsTag   tag;
} BiteStream;


// internal: inserted at the beginning of a finalized BiteStream
typedef struct _bsStreamHeader {
    int magic;
    int numtags;
    int length;
} bsStreamHeader;

#define BS_MAGIC 0x45546942

#define BSF_DONTFREEBUF 1   // flag: do not free(bs->buf) in bsFree()



// Allocates and initializes an empty BiteStream.
BiteStream *bsAlloc(void);

// Clears the tags in a BiteStream, allowing reuse of the data buffer
void bsClear(BiteStream *s);

// Frees the memory occupied by a BiteStream and its storage.
// If the BiteStream was returned by bsDecode(), the buffer
// supplied to it WILL NOT be freed.
void bsFree(BiteStream *s);

// Examines a BiteStream and prints the findings into stderr.
// Intended for debugging purposes.
void bsDump(char *buf);


// Finalizes a BiteStream for sending over a socket or writing to file.
// You can proceed to write s->length bytes from s->buf.
void bsFinalize(BiteStream *s);

// "Decodes" a BiteStream read from a socket or file. In practice,
// attaches the supplied data buffer as the bitestream's storage.
// Appending more tags to it is discouraged, and is possible ONLY if
// buf can be realloc()ed (the exact pointer was returned by malloc())!

// Returns NULL if the data isn't a proper, finalized stream.
BiteStream *bsDecode(char *buf);

// Gets the next tag in the stream. Returns a pointer to
// s->tag, or NULL if there are no more tags.
bsTag *bsNextTag(BiteStream *s);

// Resets the BiteStream's read position to the first tag.
void bsRewind(BiteStream *s);

// Appends an int-type tag to the stream.
char *bsAddInt(BiteStream *s,     int tag, int value);
// more primitive types
char *bsAddFloat(BiteStream *s,   int tag, float value);
char *bsAddDouble(BiteStream *s,  int tag, double value);
// Appends a null-terminated string-type tag to the stream.
char *bsAddStr(BiteStream *s,     int tag, const char *string);
// Appends a binary data block-type tag to the stream.
// The data pointer may be NULL, in which case space is
// reserved in the stream and you can fill in the data later.
// The minimum length is 1 byte, maximum 1073741823.
// Returns a pointer to the data in the stream (use this if
// you want to fill in the data later).
char *bsAddBin(BiteStream *s,     int tag, const void *data, int length);

// named tag versions of the above (a string label instead of an integer)
char *bsAddNamedInt(BiteStream *s,    const char *name, int value);
char *bsAddNamedFloat(BiteStream *s,  const char *name, float value);
char *bsAddNamedDouble(BiteStream *s, const char *name, double value);
char *bsAddNamedStr(BiteStream *s,    const char *name, const char *string);
char *bsAddNamedBin(BiteStream *s,    const char *name, const void *data, int length);

#ifdef __cplusplus
}
#endif

#endif

